﻿/********
* 
* 
*  Description:
*  Create By kain.hong at 11/22/2010 11:03:29 AM
*  
*
*  Revision History:
*  Date                  Who                 What
*  
* 
*/
#region namespace

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using Cherry.Agile.Framework.Dynamic;
using System.Linq.Expressions;
using System.Reflection;
using Cherry.Agile.Framework.Query;
using CR = System.Security.Cryptography;
using Cherry.Agile.Globalization;
using System.Globalization;
#endregion


namespace Cherry.Agile.Framework
{
    /// <summary>
    /// 扩展方法
    /// </summary>
    public static class Helper
    {

        public static void AddRange<T>(this ICollection<T> instance, IEnumerable<T> collection)
        {
            foreach (T item in collection)
            {
                instance.Add(item);
            }
        }

        /// <summary>
        /// 扩展Foreach方式
        /// </summary>
        /// <typeparam name="T">类型T</typeparam>
        /// <param name="ie">迭代器</param>
        /// <param name="action">行为委托</param>
        public static void ForEach<T>(this IEnumerable<T> ie, Action<T> action)
        {
            foreach (var item in ie)
            {
                action(item);
            }
        }

        /// <summary>
        /// 查询元素位置
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="lst">IEnumerable</param>
        /// <param name="predicate">Predicate</param>
        /// <returns></returns>
        public static int IndexOf<T>(this IEnumerable<T> lst, Predicate<T> predicate)
        {
            var index = -1;
            foreach (var item in lst)
            {
                index += 1;
                if (predicate(item))
                    return index;
            }
            return -1;
        }

        /// <summary>
        /// 字符转换为数字
        /// </summary>
        /// <param name="value">输入</param>
        /// <returns>转换成功的数字,如果失败返回0</returns>
        public static int ToInt(this string value)
        {
            int result = 0;
            if (int.TryParse(value, out result))
                return result;
            return result;
        }

        /// <summary>
        /// 是否为空
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool HasValue(this string value)
        {
            return !string.IsNullOrEmpty(value);
        }

        /// <summary>
        /// 字符转换为数字
        /// </summary>
        /// <param name="value">输入</param>
        /// <returns>转换成功的数字</returns>
        public static int? ToNullInt(this string value)
        {
            int result = 0;
            if (int.TryParse(value, out result))
                return result;
            return null;
        }


        public static bool IsNullOrEmpty(this string str)
        {
            return string.IsNullOrWhiteSpace(str);
        }


        /// <summary>
        /// 将字符转换成对应的枚举类型
        /// </summary>
        /// <typeparam name="T">枚举类型</typeparam>
        /// <param name="value">字符</param>
        /// <returns>对应的枚举值</returns>
        public static T ToEnum<T>(this string value)
        {
            return (T)Enum.Parse(typeof(T), value);
        }

        /// <summary>
        /// Convert String To DateTime
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static DateTime ToDateTime(this string value)
        {
            DateTime time;
            DateTime.TryParse(value, out time);
            return time;
        }

        /// <summary>
        /// 相加
        /// </summary>
        /// <param name="add1"></param>
        /// <param name="add2"></param>
        /// <returns></returns>
        public static double Add(this double d1, double d2)
        {
            return (double)((decimal)d1 + (decimal)d2);
        }
        /// <summary>
        /// 相减
        /// </summary>
        /// <param name="d1"></param>
        /// <param name="d2"></param>
        /// <returns></returns>
        public static double Sub(this double d1, double d2)
        {
            return (double)((decimal)d1 - (decimal)d2);
        }
        /// <summary>
        /// 相乖
        /// </summary>
        /// <param name="d1"></param>
        /// <param name="d2"></param>
        /// <returns></returns>
        public static double Mul(this double d1, double d2)
        {
            return (double)((decimal)d1 * (decimal)d2);
        }
        /// <summary>
        /// 相除
        /// </summary>
        /// <param name="d1"></param>
        /// <param name="d2"></param>
        /// <returns></returns>
        public static double Div(this double d1, double d2)
        {
            return d2 == 0 ? 0 : (double)((decimal)d1 / (decimal)d2);
        }

        /// <summary>
        /// 将数组转换为符号分隔的字符串
        /// </summary>
        /// <param name="arr"></param>
        /// <param name="split">分隔符</param>
        /// <returns></returns>
        public static string Join<T>(this IEnumerable<T> arr, string key, int splitCount,string split, bool isString = false)
        {
            string result = string.Empty;
            if (arr == null || !arr.GetEnumerator().MoveNext())
            {
                return result;
            }
            List<List<T>> allSplits = new List<List<T>>();
            int count = 0;
            List<T> temps = new List<T>();
            foreach (var id in arr)
            {
                if (count > splitCount)
                {
                    count = 0;
                    allSplits.Add(temps);
                    temps = new List<T>();
                }
                temps.Add(id);
                count++;
            }

            if (temps.Count > 0)
            {
                allSplits.Add(temps);
            }

            StringBuilder sb = new StringBuilder(256);

            foreach (var item in allSplits)
            {
                if (!isString)
                {
                    sb.AppendFormat(" {0} IN ({1}) OR", key, string.Join(split, item));
                }
                else
                {
                    sb.AppendFormat(" {0} IN ('{1}') OR", key, string.Join(string.Format("'{0}'", split), item));
                }
            }
            if (sb.Length > 0)
            {
                sb.Remove(sb.Length - 3, 3);
                sb.Append(")");
                sb.Insert(0, "(");
                result = sb.ToString();
            }
            return result;
        }

        /// <summary>
        /// 去除所有空格
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string RemoveSpace(this string str)
        {
            if (str.IsNullOrEmpty()) return "";
            return str.Replace("", " ").Replace("\r", "").Replace("\n", "");
        }

        /// <summary>
        /// 返回值或DBNull.Value
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static object DBValueOrNull(this string str)
        {
            if (str.IsNullOrEmpty())
            {
                return null;
            }
            else
            {
                return str;
            }
        }

        public static Guid ToGuid(this string str)
        {
            Guid test;
            if (Guid.TryParse(str, out test))
            {
                return test;
            }
            else
            {
                return Guid.Empty;
            }
        }

        /// <summary>
        /// 过滤sql
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string ReplaceSql(this string str)
        {
            str = str.Replace("'", "").Replace("--", " ").Replace(";", "");
            return str;
        }

        /// <summary>
        /// 截取字符串，汉字两个字节，字母一个字节
        /// </summary>
        /// <param name="str">字符串</param>
        /// <param name="strLength">字符串长度</param>
        /// <returns></returns>
        public static string Interruption(this string str, int len, string show)
        {
            ASCIIEncoding ascii = new ASCIIEncoding();
            int tempLen = 0;
            string tempString = "";
            byte[] s = ascii.GetBytes(str);
            for (int i = 0; i < s.Length; i++)
            {
                if ((int)s[i] == 63)
                { tempLen += 2; }
                else
                { tempLen += 1; }
                try
                { tempString += str.Substring(i, 1); }
                catch
                { break; }
                if (tempLen > len) break;
            }
            //如果截过则加上半个省略号 
            byte[] mybyte = System.Text.Encoding.Default.GetBytes(str);
            if (mybyte.Length > len)
                tempString += show;
            tempString = tempString.Replace("&nbsp;", " ");
            tempString = tempString.Replace("&lt;", "<");
            tempString = tempString.Replace("&gt;", ">");
            tempString = tempString.Replace('\n'.ToString(), "<br>");
            return tempString;
        }


        /// <summary>
        /// 截取字符串，汉字两个字节，字母一个字节
        /// </summary>
        /// <param name="str">字符串</param>
        /// <param name="strLength">字符串长度</param>
        /// <returns></returns>
        public static string CutString(this string str, int len, string show = "...")
        {
            return Interruption(str, len, show);
        }

        /// <summary>
        /// 获取左边多少个字符
        /// </summary>
        /// <param name="str"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public static string Left(this string str, int len)
        {
            if (str == null || len < 1) { return ""; }
            if (len < str.Length)
            { return str.Substring(0, len); }
            else
            { return str; }
        }

        /// <summary>
        /// 获取右边多少个字符
        /// </summary>
        /// <param name="str"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public static string Right(this string str, int len)
        {
            if (str == null || len < 1) { return ""; }
            if (len < str.Length)
            { return str.Substring(str.Length - len); }
            else
            { return str; }
        }

        /// <summary>
        /// 得到实符串实际长度
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static int Size(this string str)
        {
            byte[] strArray = System.Text.Encoding.Default.GetBytes(str);
            int res = strArray.Length;
            return res;
        }

        

       

        /// <summary>
        /// 过滤js脚本
        /// </summary>
        /// <param name="strFromText"></param>
        /// <returns></returns>
        public static string RemoveScript(this string html)
        {
            if (html.IsNullOrEmpty()) return string.Empty;
            System.Text.RegularExpressions.Regex regex1 = new System.Text.RegularExpressions.Regex(@"<script[\s\S]+</script *>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            System.Text.RegularExpressions.Regex regex2 = new System.Text.RegularExpressions.Regex(@" href *= *[\s\S]*script *:", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            System.Text.RegularExpressions.Regex regex3 = new System.Text.RegularExpressions.Regex(@" on[\s\S]*=", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            System.Text.RegularExpressions.Regex regex4 = new System.Text.RegularExpressions.Regex(@"<iframe[\s\S]+</iframe *>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            System.Text.RegularExpressions.Regex regex5 = new System.Text.RegularExpressions.Regex(@"<frameset[\s\S]+</frameset *>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            html = regex1.Replace(html, ""); //过滤<script></script>标记
            html = regex2.Replace(html, ""); //过滤href=javascript: (<A>) 属性
            html = regex3.Replace(html, " _disibledevent="); //过滤其它控件的on...事件
            html = regex4.Replace(html, ""); //过滤iframe
            html = regex5.Replace(html, ""); //过滤frameset
            return html;
        }

        /// <summary>
        /// 替换页面标签
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        public static string RemovePageTag(this string html)
        {
            if (html.IsNullOrEmpty()) return string.Empty;
            System.Text.RegularExpressions.Regex regex0 = new System.Text.RegularExpressions.Regex(@"<!DOCTYPE[^>]*>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            System.Text.RegularExpressions.Regex regex1 = new System.Text.RegularExpressions.Regex(@"<html\s*", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            System.Text.RegularExpressions.Regex regex2 = new System.Text.RegularExpressions.Regex(@"<head[\s\S]+</head\s*>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            System.Text.RegularExpressions.Regex regex3 = new System.Text.RegularExpressions.Regex(@"<body\s*", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            System.Text.RegularExpressions.Regex regex4 = new System.Text.RegularExpressions.Regex(@"<form\s*", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            System.Text.RegularExpressions.Regex regex5 = new System.Text.RegularExpressions.Regex(@"</(form|body|head|html)>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            html = regex0.Replace(html, ""); //过滤<html>标记
            html = regex1.Replace(html, "<html\u3000 "); //过滤<html>标记
            html = regex2.Replace(html, ""); //过滤<head>属性
            html = regex3.Replace(html, "<body\u3000 "); //过滤<body>属性
            html = regex4.Replace(html, "<form\u3000 "); //过滤<form>属性
            html = regex5.Replace(html, "</$1\u3000>"); //过滤</html></body></head></form>属性
            return html;
        }

        /// <summary>
        /// 取得html中的图片
        /// </summary>
        /// <param name="HTMLStr"></param>
        /// <returns></returns>
        public static string GetImg(this string text)
        {
            string str = string.Empty;
            Regex r = new Regex(@"<img\s+[^>]*\s*src\s*=\s*([']?)(?<url>\S+)'?[^>]*>", //注意这里的(?<url>\S+)是按正则表达式中的组来处理的，下面的代码中用使用到，也可以更改成其它的HTML标签，以同样的方法获得内容！
            RegexOptions.Compiled);
            Match m = r.Match(text.ToLower());
            if (m.Success)
                str = m.Result("${url}").Replace("\"", "").Replace("'", "");
            return str;
        }
        /// <summary>
        /// 取得html中的所有图片
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static string[] GetImgs(this string text)
        {
            List<string> imgs = new List<string>();
            string pat = @"<img\s+[^>]*\s*src\s*=\s*([']?)(?<url>\S+)'?[^>]*>";
            Regex r = new Regex(pat, RegexOptions.Compiled);
            Match m = r.Match(text.ToLower());
            while (m.Success)
            {
                imgs.Add(m.Result("${url}").Replace("\"", "").Replace("'", ""));
                m = m.NextMatch();
            }
            return imgs.ToArray();
        }

        /// <summary>
        /// 字符串是否包含标点符号(不包括_下画线)
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool InPunctuation(this string str)
        {
            foreach (char c in str.ToCharArray())
            {
                if (char.IsPunctuation(c) && c != '_')
                    return true;
            }
            return false;

        }
        /// <summary>
        /// 去除字符串标点符号和空字符
        /// </summary>
        /// <param name="sourceString"></param>
        /// <returns></returns>
        public static string RemovePunctuationOrEmpty(this string str)
        {
            StringBuilder NewString = new StringBuilder(str.Length);
            char[] charArr = str.ToCharArray();
            foreach (char symbols in charArr)
            {
                if (!char.IsPunctuation(symbols) && !char.IsWhiteSpace(symbols))
                {
                    NewString.Append(symbols);
                }
            }
            return NewString.ToString();
        }


        /// <summary>
        /// 返回带星期的日期格式
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public static string ToDateWeekString(this DateTime date)
        {
            string week = string.Empty;
            switch (date.DayOfWeek)
            {
                case DayOfWeek.Friday: week = "五"; break;
                case DayOfWeek.Monday: week = "一"; break;
                case DayOfWeek.Saturday: week = "六"; break;
                case DayOfWeek.Sunday: week = "日"; break;
                case DayOfWeek.Thursday: week = "四"; break;
                case DayOfWeek.Tuesday: week = "二"; break;
                case DayOfWeek.Wednesday: week = "三"; break;
            }
            return date.ToString("yyyy年M月d日 ") + "星期" + week;
        }


        /// <summary>
        /// 格式化字符 格式:hello {youname};
        /// </summary>
        /// <param name="format">格式化字符串</param>
        /// <param name="fun">回调函数：@p0 被替换字符名称 @p1 格式 return 返回值</param>
        /// <returns>格式化结果></returns>
        /// <example><coce>
        /// <![CDATA[
        ///  string format = "href='http:\\localhost\\DataPresentation\\{page}.aspx?id={Id}'";
        ///  string expected = "href='http:\\localhost\\DataPresentation\\TestView.aspx?id=1'";
        ///  string actual;
        ///  actual = Helper.Format(format, (field, f) =>
        ///     {
        ///         if (field == "Id")
        ///             return string.Format(f, 1);
        ///         else
        ///             return string.Format(f, "TestView");
        ///     });
        ///  Assert.AreEqual(expected, actual);
        /// ]]>
        /// </coce>
        /// </example>
        public static string Format(this string format, Func<string, string, string> fun)
        {
            var reg = new Regex(@"{(?<name>\w+)[\:\S]*?}");
            //reg.Replace(format, 
            return reg.Replace(format, new MatchEvaluator(m =>
            {
                string field = m.Groups["name"].Value;
                string f = m.Groups[0].Value.Replace(field, "0");
                return fun(field, f);

            }));
        }

        public static string FormatWith(this string instance, params object[] args)
        {
            return string.Format(CultureInfo.CurrentCulture, instance, args);
        }

        /// <summary>
        /// 格式化字符 格式:hello {youname};
        /// </summary>
        /// <param name="dict">键值对</param>
        /// <param name="format">字符格式</param>
        /// <returns>格式化结果</returns>
        /// <example><code><![CDATA[
        ///    Dictionary<string, object> dict = new Dictionary<string, object>();
        ///    dict.Add("value", 12.3m);
        ///    string format = "Product price is {value:00.00}";
        ///    string expected = "Product price is 12.30";
        ///    string actual;
        ///    actual = Helper.Format(dict, format);
        ///    Assert.AreEqual(expected, actual);
        ///  
        /// ]]></code></example>
        public static string Format(this Dictionary<string, object> dict, string format)
        {
            return Format(format, (field, f) =>
            {
                object value = null;
                dict.TryGetValue(field, out value);
                return string.Format(f, value);
            });
        }

        /// <summary>
        /// 返回带星期的日期时间格式
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public static string ToDateTimeWeekString(this DateTime date)
        {
            string week = string.Empty;
            switch (date.DayOfWeek)
            {
                case DayOfWeek.Friday: week = "五"; break;
                case DayOfWeek.Monday: week = "一"; break;
                case DayOfWeek.Saturday: week = "六"; break;
                case DayOfWeek.Sunday: week = "日"; break;
                case DayOfWeek.Thursday: week = "四"; break;
                case DayOfWeek.Tuesday: week = "二"; break;
                case DayOfWeek.Wednesday: week = "三"; break;
            }
            return date.ToString("yyyy年M月d日H时m分") + " 星期" + week;
        }

        /// <summary>
        /// 为多语言字符串追加":"
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string Colon(this string value)
        {
            return value + RS.GetString("Remp_Colon");
        }

        public static Guid NewSequentialGuid() {
            byte[] uid = Guid.NewGuid().ToByteArray();
            byte[] binDate = BitConverter.GetBytes(DateTime.UtcNow.Ticks);

            byte[] secuentialGuid = new byte[uid.Length];

            secuentialGuid[0] = uid[0];
            secuentialGuid[1] = uid[1];
            secuentialGuid[2] = uid[2];
            secuentialGuid[3] = uid[3];
            secuentialGuid[4] = uid[4];
            secuentialGuid[5] = uid[5];
            secuentialGuid[6] = uid[6];
            // set the first part of the 8th byte to '1100' so     
            // later we'll be able to validate it was generated by us   
            secuentialGuid[7] = (byte)(0xc0 | (0xf & uid[7]));
            // the last 8 bytes are sequential,    
            // it minimizes index fragmentation   
            // to a degree as long as there are not a large    
            // number of Secuential-Guids generated per millisecond  
            secuentialGuid[9] = binDate[0];
            secuentialGuid[8] = binDate[1];
            secuentialGuid[15] = binDate[2];
            secuentialGuid[14] = binDate[3];
            secuentialGuid[13] = binDate[4];
            secuentialGuid[12] = binDate[5];
            secuentialGuid[11] = binDate[6];
            secuentialGuid[10] = binDate[7];

            return new Guid(secuentialGuid);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> ToLambda<T>(this QueryInformation query)
        {
            if (query.Parameters == null || query.Parameters.Count == 0)
                return c => true;

            query.Parameters[0].Comperation = string.Empty;
            var values = query.Parameters.Select(
                 (c) =>
                 {
                     if (string.Compare(c.OpenParen, "in", true) == 0)
                     {
                         var val = c.Value as IEnumerable;
                         if (val == null)
                             throw new ArgumentException("当操作符是in时，值必须为集合");
                         return GetInExpression(typeof(T), c.Name, val);
                     }
                     else
                     {
                         if (c.ValueType == null || (c.Value == null && c.ValueType == "String"))
                             return string.Empty;
                         else
                             return c.Value;
                     }
                 }
             ).ToArray();

            string[] expressions = query.Parameters.Select((p, index) =>
            {
                return GetExpression(p, index, typeof(T));
            }).ToArray();

            var expression = string.Join(" ", expressions).TrimStart("AND".ToCharArray());

            var fun = DynamicExpressionParsor.ParseLambda<T, bool>(expression, values);//.Compile();

            return fun;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="paging"></param>
        /// <returns></returns>
        public static IQueryable<T> Paging<T>(this IQueryable<T> query, Pagination paging)
        {
            if( paging != null)
                return paging.ParseQuery(query) as IQueryable<T>;
            return query;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="query"></param>
        /// <param name="paging"></param>
        /// <example>
        /// <code>
        /// <![CDATA[
        ///  public List<CustomerOrderView> GetCustomerOrders( Cherry.Agile.Framework.Query.Pagination pagenation)
        ///  {
        ///      var cs = CreateQuery<Customer>();//EF需要先将查询对象定义成变量，否则会出现无法解析的错误
        ///      var os = CreateQuery<Order>();//EF需要先将查询对象定义成变量，否则会出现无法解析的错误
        ///  
        ///      var q = from c in cs
        ///              from o in os
        ///              where c.CustomerID == o.CustomerID
        ///              select new { o.CustomerID, o.OrderID, c.ContactName }; //先查询一个匿名对象，不支持直接返回视图对象。
        ///  
        ///      var count = q.Count();
        ///  
        ///      q = q.Paging(pagenation);
        ///  
        ///      return (from c in q
        ///              select new CustomerOrderView { CustomerId = c.CustomerID,
        ///                                             CustomerName = c.ContactName, 
        ///                                             OrderId = c.OrderID }
        ///             ).ToList();//返回视图对象。
        ///  }
        ///  
        /// //.....
        /// using (var scope = new DbConnectionScope(ConnectionName))
        /// {
        ///     using (var repository = new CustomerRepository())
        ///     {
        ///         var p = new Cherry.Agile.Framework.Query.Pagination() { Paging = true, 
        ///                                                             PageSize = 25 };
        ///         p.OrderBy<Customer>(c => c.ContactName);
        ///
        ///         var result = repository.GetCustomerOrders(p);
        ///         
        ///         Assert.IsTrue(p.RowCount.HasValue && p.RowCount.Value > 0);
        ///     }
        /// }
        /// ]]>
        /// </code>
        /// </example>
        /// <returns></returns>
        public static IQueryable Paging(this IQueryable query, Pagination paging)
        {
            if (paging != null)
                return paging.ParseQuery(query);
            return query;
        }

        /// <summary>
        /// 获取字符的MD5
        /// </summary>
        /// <param name="val">字符串</param>
        /// <returns></returns>
        public static string MD5(this string val)
        {
            if (string.IsNullOrEmpty(val))
                return string.Empty;

            string result = string.Empty;
            CR.MD5 md5 = CR.MD5.Create(); 
            byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(val));

            result = BitConverter.ToString(s).Replace("-", string.Empty);

            return result;
        }

        private static Expression GetInExpression(Type type, string property, IEnumerable source)
        {
            var p1 = Expression.Parameter(type, "x");
            var me = Expression.MakeMemberAccess(p1, type.GetProperty(property, BindingFlags.Public | BindingFlags.Instance));
            if (me == null)
                throw new ArgumentException("没有找到匹配的属性：" + property);
            var q = source.AsQueryable();
            var fun = Expression.Call(
                    typeof(Queryable), "Contains",
                    new Type[] { q.ElementType },
                    q.Expression, me);
            return Expression.Lambda(fun, p1);
        }

        private static string GetExpression(QueryParameter parameter, int index, Type itemType)
        {
            string expression;
            var type = parameter.ValueType;
            if (type == null)
                type = "String";
            if (parameter.Operator == "Contains"
                || parameter.Operator == "StartsWith"
                || parameter.Operator == "EndsWith")
                expression = string.Format("{0}.{1}(@{2})", parameter.Name, parameter.Operator, index);
            else if (string.Compare(parameter.Operator, "in", true) == 0)
            {
                expression = string.Format("@{0}(it)", index);
            }
            else
                expression = string.Format(" {0} {1} @{2} ", parameter.Name, parameter.Operator, index);

            return string.Format("{0} {1} {2} {3}", parameter.Comperation, parameter.OpenParen, expression, parameter.CloseParen);
        }
         
        #region object convert
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="Tfrom"></typeparam>
        /// <typeparam name="Tto"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public static Tto ConvertTo<Tfrom, Tto>(Tfrom value)
            where Tto : class, new() 
            where Tfrom:class
        {
            if (value == default(Tfrom))
                return default(Tto);
            
            var result = new Tto();
            var ps = typeof(Tfrom).GetProperties(false, false);

            foreach (var p in ps)
            {
                var val = value.GetValue(p.Name);
                result.SetValue(p.Name, val);
            }

            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="Tfrom"></typeparam>
        /// <typeparam name="Tto"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public static List<Tto> ConvertTo<Tfrom, Tto>(this List<Tfrom> value)
            where Tto : class, new()
            where Tfrom : class
        {
            return value.Select(c => ConvertTo<Tfrom, Tto>(c)).ToList();
        }

         
        #endregion

        /// <summary>
        /// 获取可空类型的实际类型
        /// </summary>
        /// <param name="conversionType"></param>
        /// <returns></returns>
        public static Type GetUnNullableType(Type conversionType)
        {
            if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                //如果是泛型方法，且泛型类型为Nullable<>则视为可空类型
                //并使用NullableConverter转换器进行转换
                var nullableConverter = new System.ComponentModel.NullableConverter(conversionType);
                conversionType = nullableConverter.UnderlyingType;
            }
            return conversionType;
        }

        private static readonly Regex NameExpression = new Regex("([A-Z]+(?=$|[A-Z][a-z])|[A-Z]?[a-z]+)", RegexOptions.Compiled);
        private static readonly Regex EntityExpression = new Regex("(&amp;|&)#([0-9]+;)", RegexOptions.Compiled);


        public static string EscapeHtmlEntities(this string html)
        {
            return EntityExpression.Replace(html, "$1\\\\#$2");
        }


        /// <summary>
        /// Determines whether this instance and another specified System.String object have the same value.
        /// </summary>
        /// <param name="instance">The string to check equality.</param>
        /// <param name="comparing">The comparing with string.</param>
        /// <returns>
        /// <c>true</c> if the value of the comparing parameter is the same as this string; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsCaseSensitiveEqual(this string instance, string comparing)
        {
            return string.CompareOrdinal(instance, comparing) == 0;
        }

        /// <summary>
        /// Determines whether this instance and another specified System.String object have the same value.
        /// </summary>
        /// <param name="instance">The string to check equality.</param>
        /// <param name="comparing">The comparing with string.</param>
        /// <returns>
        /// <c>true</c> if the value of the comparing parameter is the same as this string; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsCaseInsensitiveEqual(this string instance, string comparing)
        {
            return string.Compare(instance, comparing, StringComparison.OrdinalIgnoreCase) == 0;
        }

        public static string ToCamelCase(this string instance)
        {

            return instance[0].ToString().ToLowerInvariant() + instance.Substring(1);
        }

        public static string AsTitle(this string value)
        {
            if (value == null)
            {
                return string.Empty;
            }

            int lastIndex = value.LastIndexOf(".", StringComparison.Ordinal);

            if (lastIndex > -1)
            {
                value = value.Substring(lastIndex + 1);
            }

            return value.SplitPascalCase();
        }

        public static T ToEnum<T>(this string value, T defaultValue)
        {
            if (!value.HasValue())
            {
                return defaultValue;
            }

            try
            {
                return (T)Enum.Parse(typeof(T), value, true);
            }
            catch (ArgumentException)
            {
                return defaultValue;
            }
        }

        public static string SplitPascalCase(this string value)
        {
            return NameExpression.Replace(value, " $1").Trim();
        }

    }
}
